#pragma once

#include "Socket.hpp"
#include "comm.hpp"
#include <sys/wait.h>

using namespace SocketModule;

// 我们希望，服务器不用关心服务的具体内容
// 即不关系，发送和接收的是什么内容，转发到上层去解决
using ioservice_t = std::function<void(std::shared_ptr<Socket> &sock, InetAddr &addr)>; //todo

class TcpServer
{
public:
    TcpServer(uint16_t port, ioservice_t service)
        : _port(port),
          _listentcpsocket(std::make_unique<TcpSocket>()),
          _isrunning(false),
          _service(service)
    {
        _listentcpsocket->BuildTcpSocket(_port);
    }
    ~TcpServer(){}

    void Start()
    {
        _isrunning = true;
        while(_isrunning)
        {
            // 获取连接
            InetAddr client; // 用户获取客户端的网络地址
            auto sock = _listentcpsocket->Accept(&client); // 返回一个shared_ptr<Socket>指向的是Tcpsocket，里面的是用来IO的文件描述符
            if(sock == nullptr){
                continue;
            }

            // 进行服务,使用多进程
            pid_t id = fork();
            if(id < 0){
                LOG(loglevel::FATAL) << "fork error";
                exit(FORK_ERR);
            }
            else if(id == 0){
                // 子进程 -> 不需要监听，关闭listensockfd
                _listentcpsocket->Close();
                if(fork() > 0) exit(OK);
                // 孙子进程
                _service(sock, client); // 服务, 从那里获取，以及客户端信息
                exit(OK);
            }
            else{
                // 父进程 -> 不需要进行IO，所以关闭掉sockfd
                sock->Close();
                waitpid(id, nullptr, 0);
            }
        }
    }

private:
    uint16_t _port;
    std::unique_ptr<Socket> _listentcpsocket;
    bool _isrunning;
    ioservice_t _service;
};